package com.sea.base.utils.voice

import android.media.AudioManager
import android.media.MediaPlayer
import android.net.Uri
import androidx.lifecycle.Lifecycle
import com.sea.base.ext.global.isHttp
import com.sea.base.ext.global.postMainSmart
import com.sea.base.ext.global.singleApplication
import com.sea.base.ext.global.throwIfDebug
import com.sea.base.ext.global.toast
import com.sea.base.ext.obs.addObserver
import com.sea.base.ext.obs.doOnDestroyed

/**
 * 基于生命周期管理，销毁之后不可恢复
 * 本身自是一个MediaPlayer单例，所以每次play都会创建一个子管理类
 */
class VoiceMediaPlayer(lifecycle: Lifecycle) {

    private var mediaPlayer: MediaPlayer? = MediaPlayer()

    var currentItem: PlayingItem? = null
        private set

    val currentUrl get() = currentItem?.urlOrPath

    val isPlaying: Boolean
        get() = mediaPlayer?.isPlaying ?: false

    init {
        lifecycle.addObserver { _, event ->
            if (event == Lifecycle.Event.ON_PAUSE) {
                currentItem?.pause()
            }
        }
        lifecycle.doOnDestroyed { destroy() }
    }

    class PlayingItem(private val player: VoiceMediaPlayer, private val mediaPlayer: MediaPlayer, val urlOrPath: String) {
        var isPlaying: Boolean = false
            private set
        var onCompletionListener: (() -> Unit)? = null
        var onPauseListener: (() -> Unit)? = null
        private var isPrepared = false

        private var onPreparedListener: (() -> Unit)? = null

        init {
            init()
        }

        private fun init() {
            if (player.currentItem != this) {
                player.currentItem?.stop()
            }
            isPrepared = false
            mediaPlayer.reset()
            try {
                if (urlOrPath.isHttp()) {
                    mediaPlayer.setDataSource(singleApplication, Uri.parse(urlOrPath))
                } else {
                    mediaPlayer.setDataSource(urlOrPath)
                }
                mediaPlayer.setAudioStreamType(AudioManager.STREAM_MUSIC)
                mediaPlayer.setOnPreparedListener {
                    postMainSmart {
                        isPrepared = true
                        onPreparedListener?.invoke()
                    }
                }
                mediaPlayer.prepareAsync()
                mediaPlayer.setOnCompletionListener {
                    isPlaying = false
                    postMainSmart {
                        onCompletionListener?.invoke()
                    }
                }
                player.currentItem = this
            } catch (e: Throwable) {
                e.printStackTrace()
                "播放失败！".toast()
                mediaPlayer.release()
                "播放失败：${urlOrPath}".throwIfDebug(e)
            }
        }

        private fun doOnPreparedStart() {
            if (isPrepared) {
                mediaPlayer.start()
            } else {
                onPreparedListener = {
                    mediaPlayer.start()
                }
            }
        }

        fun play() {
            try {
                isPlaying = true
                if (player.currentItem != this) {
                    init()
                }
                doOnPreparedStart()
            } catch (e: Throwable) {
                e.printStackTrace()
            }
        }

        fun stop() {
            if (player.currentItem != this) return
            if (!isPrepared) return
            pause()
            mediaPlayer.stop()
        }

        fun pause() {
            if (player.currentItem != this) return
            if (!isPrepared) return
            if (isPlaying) {
                isPlaying = false
                mediaPlayer.pause()
                onPauseListener?.invoke()
            }
        }
    }

    /**
     * 创建一个item
     */
    fun newItem(urlOrPath: String): PlayingItem {
        val mediaPlayer = mediaPlayer ?: throw IllegalStateException("不支持在destroy后调用")
        return PlayingItem(this, mediaPlayer, urlOrPath)
    }

    /**
     * 创建一个item并立即播放对应URL内容
     */
    fun play(urlOrPath: String) = newItem(urlOrPath).also { it.play() }

    /**
     * 销毁，销毁之后不能再次调用
     */
    fun destroy() {
        currentItem?.stop()
        currentItem = null
        mediaPlayer?.reset()
        mediaPlayer?.release()
        mediaPlayer = null
    }
}